package handler

import (
	"log"
	"strconv"
	"time"
	"ulcdkey/conf"
	"ulcdkey/db"
	"ulcdkey/tool"

	"github.com/labstack/echo/v4"
)

/*----------- CDK -----------------------*/

// 根据cdk类获取cdk列表
func GetCdkList(c echo.Context) (err error) {
	var r ResponseResult
	t := time.Now()
	uid := tool.GetUid(c)
	cdks := new(db.Cdk)

	cdkTypeIdStr := c.FormValue("cdkTypeId")
	pageStr := c.FormValue("page")
	limitStr := c.FormValue("limit")
	statusStr := c.FormValue("status") // 0可使用 1已使用 2已过期

	cdks.CdkTypeId, err = strconv.Atoi(cdkTypeIdStr)
	if err != nil {
		log.Println("cdkTypeId参数错误 err:", err)
		r.Code = -1
		r.Msg = "cdkTypeId参数错误,err=" + err.Error()
		return c.JSON(200, r)
	}

	page, err := strconv.Atoi(pageStr)
	if err != nil {
		log.Println("page参数错误 err:", err)
		r.Code = -1
		r.Msg = "page参数错误,err=" + err.Error()
		return c.JSON(200, r)
	}

	limit, err := strconv.Atoi(limitStr)
	if err != nil {
		log.Println("limit参数错误 err:", err)
		r.Code = -1
		r.Msg = "limit参数错误,err=" + err.Error()
		return c.JSON(200, r)
	}

	status, err := strconv.Atoi(statusStr)
	if err != nil || (status != 0 && status != 1 && status != 2) {
		log.Println("status参数错误 err:", err)
		r.Code = -1
		r.Msg = "status参数错误,err=" + err.Error()
		return c.JSON(200, r)
	}

	as, counts, err := cdks.GetCdkListByTypeId(page, limit, status)
	if err != nil {
		log.Println("GetCdkListByTypeId err:", err)
		r.Code = -1
		r.Msg = "获取cdk列表失败,err=" + err.Error()
		return c.JSON(200, r)
	}

	r.Data = map[string]interface{}{
		"results": as,
		"counts":  counts,
	}
	log.Println(c.Request().URL, "uid =", uid, "【耗时:", time.Now().Sub(t).Seconds(), "s】")
	return c.JSON(200, r)
}

// 新增 n 条cdk
func AddSomeCdk(c echo.Context) (err error) {
	var r ResponseResult
	t := time.Now()
	uid := tool.GetUid(c)
	cdks := new(db.Cdk)
	userInfo := tool.GetVisitUserInfo(c)

	cdkTypeIdStr := c.FormValue("cdkTypeId")
	prefix := c.FormValue("prefix")
	lensStr := c.FormValue("lens") // 除前缀外长度
	numsStr := c.FormValue("nums") // 生成数量

	cdks.CdkTypeId, err = strconv.Atoi(cdkTypeIdStr)
	if err != nil {
		log.Println("cdkTypeId err:", err)
		r.Code = -1
		r.Msg = "cdkTypeId参数错误,err=" + err.Error()
		return c.JSON(200, r)
	}

	lens, err := strconv.Atoi(lensStr)
	if err != nil {
		log.Println("lens err:", err)
		r.Code = -1
		r.Msg = "lens参数错误,err=" + err.Error()
		return c.JSON(200, r)
	}

	nums, err := strconv.Atoi(numsStr)
	if err != nil {
		log.Println("nums err:", err)
		r.Code = -1
		r.Msg = "nums参数错误,err=" + err.Error()
		return c.JSON(200, r)
	}

	err = cdks.AddSomeCdk(prefix, nums, lens, userInfo)
	if err != nil {
		log.Println("AddSomeCdk err:", err)
		r.Code = -1
		r.Msg = "新增cdk失败,err=" + err.Error()
		return c.JSON(200, r)
	}

	log.Println(c.Request().URL, "uid =", uid, "【耗时:", time.Now().Sub(t).Seconds(), "s】")
	return c.JSON(200, r)
}

//获得cdk兑换队列长度
func GetCdkWorkerlength(c echo.Context) (err error) {
	cdk := new(db.Cdk)
	msg := cdk.GetWorkerlength()

	return c.String(200, msg)
}

/*---------------- 客户端 ---------------------*/
type UseCdkResult struct {
	Code string      `json:"code"`
	Data interface{} `json:"data"`
}

// 使用cdk
func UseCdk(c echo.Context) (err error) {
	var r UseCdkResult
	t := time.Now()

	gameVersionStr := c.FormValue("gameVersion")

	r.Code = "999"
	gameVersion := 0
	if gameVersionStr != "" {
		gameVersion, err = strconv.Atoi(gameVersionStr)
		if err != nil {
			log.Println("UseCdk err:", err)

			r.Data = "参数错误，领取失败"
			return c.JSON(200, r)
		}
	}

	var task = new(db.WorkerTask)
	task.UserId = c.FormValue("userId")
	task.AppId = c.FormValue("appId")
	task.ChannelId = c.FormValue("channelId")
	task.Cdkey = c.FormValue("cdkStr")
	task.GameVersion = gameVersion
	task.ResChannel = make(chan *db.CdkRes, 1)
	task.Platform = c.FormValue("platform") //android h5 ios

	hashNum := tool.StringToHashNum(task.AppId) // 字符串转hash数字

	index := hashNum % conf.Conf.CdkWorkerNum // 取余,获取索引

	targetWorker := db.WorkerList[index] // 索引对应woker

	targetWorker.Post(task)

	select {
	case res := <-task.ResChannel:

		r.Code = res.Code
		r.Data = res.Data

		log.Println(c.Request().URL, "【耗时:", time.Now().Sub(t).Seconds(), "s】")
		return c.JSON(200, r)

	case <-time.After(time.Duration(conf.Conf.TimeOutSecond) * time.Second):

		// 0  队列中 1 正在兑换  -1 超时
		if task.Status != 1 {

			// 通知worker超时，drop掉task
			task.IsTimeout = true //多线程 超时更新不同步
			task.Status = -1

			log.Println("UseCdk err:系统超时，领取失败")

			r.Code = "-1"
			r.Data = "系统超时，领取失败"
			log.Println(c.Request().URL, "【耗时:", time.Now().Sub(t).Seconds(), "s】")
			return c.JSON(200, r)
		}

		// 任务已经在执行中
		res := <-task.ResChannel

		r.Data = res.Data
		r.Code = res.Code

		log.Println(c.Request().URL, "【耗时:", time.Now().Sub(t).Seconds(), "s】")
		return c.JSON(200, r)
	}
}
